package com.example.nick.bodyapplication.aes;

import android.util.Base64;
import android.util.Log;

import java.nio.charset.StandardCharsets;
import java.util.Locale;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESCBCUtil {
    //密码
    public static final String KEY = "!moiot@xc#ipc$00";
    //iv偏移量
    public static final String IV = "0000000000000000";

    public static final String KEY_S = "0000181c-0000-1000-8000-00805f9b34fb";
    public static final String KEY_W = "0000181d-0000-1000-8000-00805f9b34fb";
    public static final String KEY_N = "0000181e-0000-1000-8000-00805f9b34fb";

    public static final String MO_CONN_RESP = "{\"code\":0,\"message\":\"MOIOT_CONN_RESP\"}";
    public static final String MO_REQ_DEVID = "{\"message\": \"MOIOT_GETDEVID_REQ\"}";
    public static final String MO_REQ_BIND_SUCCESS = "{\"message\": \"MOIOT_BIND_SUCCESS_REQ\"}";
    public static final String MO_REQ_SETWIFI = "{\"message\":\"MOIOT_WIFISET_REQ\",\"data\": {\"ssid\": \"ChinaNet-tUdE\",\"passwd\": \"np6usuhd\"}}";

    public static final String MOIOT_GETDEVID_RESP = "MOIOT_GETDEVID_RESP";
    public static final String MOIOT_NOTYDEVID_RESP = "MOIOT_NOTYDEVID_RESP";
    public static final String MOIOT_WIFISET_RESP = "MOIOT_WIFISET_RESP";
    public static final String MOIOT_CONSUCESS_REQ = "MOIOT_CONSUCESS_REQ";
    public static final String MOIOT_CONSUCESS_RESP = "MOIOT_CONSUCESS_RESP";
    public static final String MOIOT_DOOR_TRIGGER_RESP = "MOIOT_DOOR_TRIGGER_RESP";

    /**
     * 加密：对字符串进行加密，并返回十六进制字符串(hex)
     *
     * @param encryptStr 需要加密的字符串
     * @return 加密后的十六进制字符串(hex)
     */
    public static String encrypt(String encryptStr, String key, String iv) {
        try {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

            /**
             * 这个地方调用BouncyCastleProvider
             *让java支持PKCS7Padding
             */
            //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);

            byte[] encrypted = cipher.doFinal(encryptStr.getBytes());


            byte[] encode64 = Base64.encode(encrypted, Base64.DEFAULT);

            String string = new String(encode64);
            Log.i("AES", "encode64:"+string);
//            return string;
                 return byte2HexStr(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static String encryptGCM(String encryptStr, String key, String iv) {
        try {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

            /**
             * 这个地方调用BouncyCastleProvider
             *让java支持PKCS7Padding
             */
            //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);

            byte[] encrypted = cipher.doFinal(encryptStr.getBytes());


            byte[] encode64 = Base64.encode(encrypted, Base64.DEFAULT);

            String string = new String(encode64);
//            Log.i("AES", "encode64:"+string);
//            return string;
            return byte2HexStr(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static String decryptGCM(String encryptedStr, String key, String iv) {
        try {
            String abc_key = "!moiot@xc#ipc$00";
            String abc_iv = "0000000000000000";
            IvParameterSpec ivParameterSpec = new IvParameterSpec(abc_iv.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(abc_key.getBytes(StandardCharsets.UTF_8), "AES");

            // DES/CBC/PKCS5Padding
            // AES/CBC/PKCS7PADDING
            // AES/CBC/NoPadding
            // AES/CBC/SSL3Padding
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);

            byte[] decode = Base64.decode(encryptedStr, Base64.DEFAULT);

            byte[] bytes = hexStr2Bytes(encryptedStr);
//            byte[] original = cipher.doFinal(decode);
            byte[] original = cipher.doFinal(bytes);

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static byte[] encryptBytes(String encryptStr, String key, String iv) {
        try {
            String abc_key = "!moiot@xc#ipc$00";
            String abc_iv = "0000000000000000";
            IvParameterSpec ivParameterSpec = new IvParameterSpec(abc_iv.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(abc_key.getBytes(StandardCharsets.UTF_8), "AES");

            /**
             * 这个地方调用BouncyCastleProvider
             *让java支持PKCS7Padding
             */
            //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
            byte[] encrypted = cipher.doFinal(encryptStr.getBytes());
            return encrypted;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return new byte[0];
    }

    /**
     * 解密：对加密后的十六进制字符串(hex)进行解密，并返回字符串
     *
     * @param encryptedStr 需要解密的，加密后的十六进制字符串
     * @return 解密后的字符串
     */
    public static String decrypt(String encryptedStr, String key, String iv) {
        try {
            String abc_key = "!moiot@xc#ipc$00";
            String abc_iv = "0000000000000000";
            IvParameterSpec ivParameterSpec = new IvParameterSpec(abc_iv.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(abc_key.getBytes(StandardCharsets.UTF_8), "AES");

            // DES/CBC/PKCS5Padding
            // AES/CBC/PKCS7PADDING
            // AES/CBC/NoPadding
            // AES/CBC/SSL3Padding
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);

            byte[] decode = Base64.decode(encryptedStr, Base64.DEFAULT);

              byte[] bytes = hexStr2Bytes(encryptedStr);
//            byte[] original = cipher.doFinal(decode);
            byte[] original = cipher.doFinal(bytes);

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * 十六进制字符串转换为byte[]
     *
     * @param hexStr 需要转换为byte[]的字符串
     * @return 转换后的byte[]
     */
    public static byte[] hexStr2Bytes(String hexStr) {


        /*对输入值进行规范化整理*/
        hexStr = hexStr.trim().replace(" ", "").toUpperCase(Locale.US);
        //处理值初始化
        int m = 0, n = 0;
        int iLen = hexStr.length() / 2; //计算长度
        byte[] ret = new byte[iLen]; //分配存储空间

        for (int i = 0; i < iLen; i++) {
            m = i * 2 + 1;
            n = m + 1;
            ret[i] = (byte) (Integer.decode("0x" + hexStr.substring(i * 2, m) + hexStr.substring(m, n)) & 0xFF);
        }
        return ret;
    }


    /**
     * byte[]转换为十六进制字符串
     *
     * @param bytes 需要转换为字符串的byte[]
     * @return 转换后的十六进制字符串
     */
    public static String byte2HexStr(byte[] bytes) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < bytes.length; n++) {
            stmp = (Integer.toHexString(bytes[n] & 0XFF));
            if (stmp.length() == 1)
                hs = hs + "0" + stmp;
            else
                hs = hs + stmp;
        }
        return hs;
    }
}
